"""
类的封装 (Encapsulation)
=====================

封装是面向对象编程的核心概念之一，指的是将数据（属性）和操作数据的方法组合在一个类中，
并隐藏对象的内部实现细节，只通过公共接口与外界交互。

封装的作用：
1. 提高代码的安全性
2. 简化编程，使用者不必了解具体的实现细节
3. 降低程序的耦合度，增强可维护性

Python中的封装实现方式：
1. 公有成员 (Public) - 可以在任何地方访问
2. 私有成员 (Private) - 以双下划线(__)开头，只能在类内部访问
3. 受保护成员 (Protected) - 以单下划线(_)开头，约定只能在类及其子类中访问
"""

# 示例1: 基本封装概念
class Student:
    def __init__(self, name, age):
        self.name = name        # 公有属性
        self.__age = age        # 私有属性
    
    def get_age(self):          # 公有方法
        """获取年龄的公有方法"""
        return self.__age
    
    def set_age(self, age):     # 公有方法
        """设置年龄的公有方法"""
        if 0 < age < 150:
            self.__age = age
        else:
            raise ValueError("年龄必须在0-150之间")

# 使用示例
# student = Student("张三", 20)
# print(student.name)      # 正常访问公有属性
# print(student.get_age()) # 通过公有方法访问私有属性
# student.set_age(25)      # 通过公有方法修改私有属性

# 示例2: 使用属性装饰器实现封装
class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age
    
    @property
    def age(self):
        """
        age属性的getter方法
        使用@property装饰器将方法转换为属性访问器
        允许像访问属性一样调用该方法: person.age
        """
        return self.__age
    
    @age.setter
    def age(self, age):
        """
        age属性的setter方法
        使用@属性名.setter装饰器定义属性的设置器
        允许像设置属性一样调用该方法: person.age = 30
        在设置时可以添加数据验证逻辑
        """
        if 0 < age < 150:
            self.__age = age
        else:
            raise ValueError("年龄必须在0-150之间")
    
    @age.deleter
    def age(self):
        """
        age属性的deleter方法（可选）
        使用@属性名.deleter装饰器定义属性的删除器
        允许使用del语句删除属性: del person.age
        """
        print("删除年龄属性")
        del self.__age

# 使用示例
# person = Person("李四", 22)
# print(person.age)    # 通过属性访问，像访问公有属性一样
# person.age = 30      # 通过属性设置，像设置公有属性一样
# del person.age       # 通过属性删除，像删除属性一样

# 示例3: 受保护成员的使用
class Animal:
    def __init__(self, name):
        self._name = name       # 受保护属性，约定只能在类及子类中使用
    
    def _protected_method(self):
        """受保护方法，约定只能在类及子类中使用"""
        return f"受保护的方法被调用，动物名称: {self._name}"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
    
    def info(self):
        # 子类可以访问父类的受保护成员
        return f"{self._protected_method()}, 品种: {self.breed}"

# @property装饰器详解：
"""
@property装饰器的作用和优势：

1. 简化访问语法：
   - 无需使用括号调用方法
   - 像访问普通属性一样访问方法

2. 数据封装与验证：
   - 可以在getter中进行计算或格式化
   - 可以在setter中进行数据验证
   - 隐藏内部实现细节

3. 向后兼容性：
   - 可以将公共属性改为需要计算的属性而不影响客户端代码
   - 可以在不改变接口的情况下添加功能

4. 属性的完整控制：
   - getter: @property
   - setter: @属性名.setter
   - deleter: @属性名.deleter

使用@property的典型场景：
1. 需要对属性访问进行控制时
2. 需要动态计算属性值时
3. 需要将简单属性改造为复杂逻辑时
4. 需要保持接口一致性时
"""

# 封装的注意事项：
"""
1. Python中的私有成员并不是真正意义上的私有，而是通过名称改写(_ClassName__attr)实现的
2. 单下划线(_)只是约定俗成的保护性标记，并不是强制性的
3. 双下划线(__)开头的成员会被Python解释器改写名称，实现真正的私有化
4. 使用@property装饰器可以更优雅地实现属性的封装
5. 封装应该遵循最小权限原则，能私有的尽量私有
"""

# 验证私有成员的名称改写机制
class TestPrivate:
    def __init__(self):
        self.__private_attr = "私有属性"
        self.public_attr = "公有属性"
    
    def __private_method(self):
        return "私有方法"
    
    def access_private(self):
        # 类内部可以访问私有成员
        return self.__private_attr, self.__private_method()

# 使用示例
# test = TestPrivate()
# print(test.public_attr)           # 正常访问
# print(test._TestPrivate__private_attr)  # 通过名称改写访问私有属性
# test._TestPrivate__private_method()     # 通过名称改写访问私有方法